// Based in gate_1410.c LADSPA Swh-plugins


/*
  rakarrack - a guitar effects software

 Gate.C  -  Noise Gate Effect
 
  Copyright (C) 2008 Daniel Vidal & Josep Andreu
  Author: Daniel Vidal & Josep Andreu

 This program is free software; you can redistribute it and/or modify
 it under the terms of version 2 of the GNU General Public License
 as published by the Free Software Foundation.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License (version 2) for more details.

 You should have received a copy of the GNU General Public License
 (version2)  along with this program; if not, write to the Free Software
 Foundation,
 Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

*/
//#include "stdafx.h"
#include <math.h>
#include "Gate.h"

#define D_PI 6.283185f
#define PI 3.141598f
#define LOG_10 2.302585f
#define LOG_2  0.693147f
#define AMPLITUDE_INTERPOLATION_THRESHOLD 0.0001f
#define FF_MAX_VOWELS 6
#define FF_MAX_FORMANTS 12
#define FF_MAX_SEQUENCE 8
#define MAX_FILTER_STAGES 5
#define RND (rand()/(RAND_MAX+1.0))
#define float float
#define F2I(f,i) (i)=((f>0) ? ( (int)(f) ) :( (int)(f-1.0f) ))
#define dB2rap(dB) (float)((expf((dB)*LOG_10/20.0f)))
#define rap2dB(rap) (float)((20*log(rap)/LOG_10))
#define CLAMP(x, low, high)  (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#define INTERPOLATE_AMPLITUDE(a,b,x,size) ( (a) + ( (b) - (a) ) * (float)(x) / (float) (size) )
#define ABOVE_AMPLITUDE_THRESHOLD(a,b) ( ( 2.0f*fabs( (b) - (a) ) / ( fabs( (b) + (a) + 0.0000000001f) ) ) > AMPLITUDE_INTERPOLATION_THRESHOLD )
#define POLY 8
#define DENORMAL_GUARD 1e-18f	// Make it smaller until CPU problem re-appears
#define SwapFourBytes(data) ( (((data) >> 24) & 0x000000ff) | (((data) >> 8) & 0x0000ff00) | (((data) << 8) & 0x00ff0000) | (((data) << 24) & 0xff000000) )

#ifdef WIN32
static inline int lrintf(float x)
{
    __asm cvtss2si eax, x
}
#endif

Gate::Gate (REALTYPE * efxoutl_, REALTYPE * efxoutr_)
{

  efxoutl = efxoutl_;
  efxoutr = efxoutr_;


  lpfl = new AnalogFilter (2, 22000, 1, 0);
  lpfr = new AnalogFilter (2, 22000, 1, 0);
  hpfl = new AnalogFilter (3, 20, 1, 0);
  hpfr = new AnalogFilter (3, 20, 1, 0);

  env = 0.0;
  gate = 0.0;
  fs = (float)SAMPLE_RATE;
  state = CLOSED;
  hold_count = 0;




}

Gate::~Gate ()
{



}



void
Gate::cleanup ()
{
  lpfl->cleanup ();
  hpfl->cleanup ();
  lpfr->cleanup ();
  hpfr->cleanup ();

}




void
Gate::setlpf (int Plpf)
{
  this->Plpf = Plpf;
  REALTYPE fr = expf (powf ((float)Plpf / 127.0f, 0.5f) * logf (25000.0f)) + 40.0f;
  lpfl->setfreq (fr);
  lpfr->setfreq (fr);
};

void
Gate::sethpf (int Phpf)
{
  this->Phpf = Phpf;
  REALTYPE fr = expf (powf ((float)Phpf / 127.0f, 0.5f) * logf (25000.0f)) + 20.0f;
  hpfl->setfreq (fr);
  hpfr->setfreq (fr);
};


void
Gate::Gate_Change (int np, int value)
{

  switch (np)
    {

    case 1:
      Pthreshold = value;
      t_level = dB2rap ((float)Pthreshold);
      break;
    case 2:
      Prange = value;
      cut = dB2rap ((float)Prange);
      break;
    case 3:
      Pattack = value;
      a_rate = 1000.0f / ((float)Pattack * fs);
      break;
    case 4:
      Pdecay = value;
      d_rate = 1000.0f / ((float)Pdecay * fs);
      break;
    case 5:
      setlpf(value);
      break;
    case 6:
      sethpf(value);
      break;
    case 7:
      Phold = value;
      hold = (float)Phold;
      break;

    }


}

int
Gate::getpar (int np)
{

  switch (np)

    {
    case 1:
      return (Pthreshold);
      break;
    case 2:
      return (Prange);
      break;
    case 3:
      return (Pattack);
      break;
    case 4:
      return (Pdecay);
      break;
    case 5:
      return (Plpf);
      break;
    case 6:
      return (Phpf);
      break;
    case 7:
      return (Phold);
      break;

    }

  return (0);

}


void
Gate::Gate_Change_Preset (int npreset)
{

  const int PRESET_SIZE = 7;
  const int NUM_PRESETS = 3;
  int presets[NUM_PRESETS][PRESET_SIZE] = {
    //0
    {0, 0, 1, 2, 96, 20, 2},
    //-5
    {0, -5, 1, 2, 96, 20, 2},
    //-20
    {0, -20, 1, 2, 96, 20, 2}
  };

  if (npreset >= NUM_PRESETS)
    npreset = NUM_PRESETS - 1;
  for (int n = 0; n < PRESET_SIZE; ++n)
    Gate_Change (n + 1, presets[npreset][n]);


}



void
Gate::out (float *efxoutl, float *efxoutr)
{


  int i;
  float sum;


  lpfl->filterout (efxoutl);
  hpfl->filterout (efxoutl);
  lpfr->filterout (efxoutr);
  hpfr->filterout (efxoutr);


  for (i = 0; i < PERIOD; ++i)
    {

      sum = fabsf (efxoutl[i]) + fabsf (efxoutr[i]);


      if (sum > env)
	env = sum;
      else
	env = sum * ENV_TR + env * (1.0f - ENV_TR);

      if (state == CLOSED)
	{
	  if (env >= t_level)
	    state = OPENING;
	}
      else if (state == OPENING)
	{
	  gate += a_rate;
	  if (gate >= 1.0)
	    {
	      gate = 1.0f;
	      state = OPEN;
	      hold_count = lrintf (hold * fs * 0.001f);
	    }
	}
      else if (state == OPEN)
	{
	  if (hold_count <= 0)
	    {
	      if (env < t_level)
		{
		  state = CLOSING;
		}
	    }
	  else
	    hold_count--;

	}
      else if (state == CLOSING)
	{
	  gate -= d_rate;
	  if (env >= t_level)
	    state = OPENING;
	  else if (gate <= 0.0)
	    {
	      gate = 0.0;
	      state = CLOSED;
	    }
	}

      efxoutl[i] *= (cut * (1.0f - gate) + gate);
      efxoutr[i] *= (cut * (1.0f - gate) + gate);

    }



};

bool Gate::SetSampleRate(unsigned int iSamplePerSec)
{
	SAMPLE_RATE = iSamplePerSec;
	lpfl->SetSampleRate(iSamplePerSec);
	lpfr->SetSampleRate(iSamplePerSec);
	hpfl->SetSampleRate(iSamplePerSec);
	hpfr->SetSampleRate(iSamplePerSec);
	fs = (float)SAMPLE_RATE;
	return true;
};

bool Gate::SetBufferSize(int nSamples)
{
	if(nSamples<=0)
	{
		return false;
	}
	PERIOD=nSamples;
	lpfl->SetBufferSize(nSamples);
	lpfr->SetBufferSize(nSamples);
	hpfl->SetBufferSize(nSamples);
	hpfr->SetBufferSize(nSamples);
	
	return true;
};